package com.xiaoyu.lanling.feature.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;

import com.github.florent37.viewanimator.ViewAnimator;
import com.xiaoyu.lanling.R;

import in.srain.cube.util.LocalDisplay;

@SuppressLint("InflateParams")
public class StatusLayout extends FrameLayout {

    private static final int STATUS_LOADING = 0;
    private static final int STATUS_EMPTY = 1;
    private static final int STATUS_ERROR = 2;
    private static final int STATUS_CONTENT = 3;

    private int mStatusType;
    private LayoutInflater mLayoutInflater;
    private ViewGroup.LayoutParams mLayoutParams;
    private View mLoadingView;
    private View mEmptyView;
    private View mErrorView;
    private Context mContext;

    private boolean mShowLoadingForInit;
    private boolean mLoadingCenter;

    public StatusLayout(Context context) {
        this(context, null);
    }

    public StatusLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StatusLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.StatusLayout);
        mShowLoadingForInit = typedArray.getBoolean(R.styleable.StatusLayout_showLoadingForInit, true);
        mLoadingCenter = typedArray.getBoolean(R.styleable.StatusLayout_loadingCenter, true);
        typedArray.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        initLayoutInflater();
        if (mShowLoadingForInit) {
            showLoading();
        }
    }

    public View getmEmptyView() {
        return mEmptyView;
    }

    public View getmErrorView() {
        return mErrorView;
    }

    private void initLayoutInflater() {
        if (mLayoutInflater == null || mLayoutParams == null) {
            mLayoutInflater = LayoutInflater.from(getContext());
            mLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        }
    }

    public void setShowLoadingForInit(boolean showLoadingForInit) {
        mShowLoadingForInit = showLoadingForInit;
    }

    public void showLoading() {
        mStatusType = STATUS_LOADING;
        if (mLoadingView == null) {
            mLoadingView = mLayoutInflater.inflate(R.layout.view_status_layout_loading, null);
            processLoadingGravity(mLoadingView, R.id.loading_view);
        }
        if (!hasView(mLoadingView)) {
            addView(mLoadingView, mLayoutParams);
        }

        showView(mStatusType);
    }

    public void showEmpty(String message) {
        mStatusType = STATUS_EMPTY;
        if (mEmptyView == null) {
            mEmptyView = mLayoutInflater.inflate(R.layout.view_status_layout_empty, null);
            processLoadingGravity(mEmptyView, R.id.empty_text);
        }
        if (!hasView(mEmptyView)) {
            addView(mEmptyView, mLayoutParams);
        }

        TextView messageText = mEmptyView.findViewById(R.id.empty_text);
        messageText.setText(message);
        showView(mStatusType);
    }

    public void showEmpty(String message, ViewGroup.LayoutParams layoutParams) {
        mStatusType = STATUS_EMPTY;
        if (mEmptyView == null) {
            mEmptyView = mLayoutInflater.inflate(R.layout.view_status_layout_empty, null);
            processLoadingGravity(mEmptyView, R.id.empty_text);
        }
        if (!hasView(mEmptyView)) {
            addView(mEmptyView, layoutParams);
        }

        TextView messageText = mEmptyView.findViewById(R.id.empty_text);
        messageText.setText(message);
        showView(mStatusType);
    }

    public void showError(CharSequence message) {
        mStatusType = STATUS_ERROR;
        if (mErrorView == null) {
            mErrorView = mLayoutInflater.inflate(R.layout.view_status_layout_error, null);
            processLoadingGravity(mErrorView, R.id.error_text);
        }
        if (!hasView(mErrorView)) {
            addView(mErrorView, mLayoutParams);
        }

        TextView messageText = mErrorView.findViewById(R.id.error_text);
        messageText.setText(message);
        showView(mStatusType);
    }

    public void showContent() {
        mStatusType = STATUS_CONTENT;
        showView(mStatusType);
    }

    public View showLazyViewWithLoading(LayoutInflater layoutInflater, @LayoutRes int resource, int delayMillis) {
        initLayoutInflater();
        showLoading();
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(() -> {
            mStatusType = STATUS_CONTENT;
            showView(mStatusType);
        }, delayMillis);
        final View contentView = layoutInflater.inflate(resource, this, false);
        if (!hasView(contentView)) {
            addView(contentView, 0, mLayoutParams);
        }
        return contentView;
    }

    public View showLazyViewWithLoading(LayoutInflater layoutInflater, @LayoutRes int resource) {
        return showLazyViewWithLoading(layoutInflater, resource, 500);
    }

    public View showLazyViewForInitData(LayoutInflater layoutInflater, @LayoutRes int resource) {
        initLayoutInflater();
        showLoading();
        final View contentView = layoutInflater.inflate(resource, this, false);
        if (!hasView(contentView)) {
            addView(contentView, 0, mLayoutParams);
        }
        return contentView;
    }

    private void showView(int type) {
        if (mLoadingView != null && hasView(mLoadingView)) {
            if (type == STATUS_LOADING) {
                showView(mLoadingView);
            } else {
                hideView(mLoadingView);
            }
        }
        if (mEmptyView != null && hasView(mEmptyView)) {
            if (type == STATUS_EMPTY) {
                showView(mEmptyView);
            } else {
                hideView(mEmptyView);
            }
        }
        if (mErrorView != null && hasView(mErrorView)) {
            if (type == STATUS_ERROR) {
                showView(mErrorView);
            } else {
                hideView(mErrorView);
            }
        }
    }

    private void processLoadingGravity(View view, @IdRes int resId) {
        if (!mLoadingCenter) {
            View loadingView = view.findViewById(resId);
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
            params.topMargin = LocalDisplay.dp2px(64);
            loadingView.setLayoutParams(params);
        }
    }

    private void showView(View view) {
        if (!hasView(view)) {
            return;
        }
        if (view.getVisibility() == VISIBLE) {
            return;
        }
        ViewAnimator.animate(view)
                .alpha(0, 1f)
                .onStart(() -> view.setVisibility(VISIBLE))
                .interpolator(new AccelerateDecelerateInterpolator())
                .duration(64)
                .start();
    }

    private void hideView(View view) {
        if (!hasView(view)) {
            return;
        }
        if (view.getVisibility() == GONE) {
            return;
        }
        ViewAnimator.animate(view)
                .alpha(1, 0f)
                .onStop(() -> {
                    view.setVisibility(GONE);
                    removeView(view);
                })
                .interpolator(new AccelerateDecelerateInterpolator())
                .duration(64)
                .start();
    }

    private boolean hasView(View view) {
        final int index = indexOfChild(view);
        return index >= 0;
    }
}
